home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
tex
/
rail.zip
/
RAIL.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-01-15
|
10KB
|
695 lines
/*
* rail.c - railroad diagram utility
*
* 09-Jul-1990 L. Rooijakkers
* 09-Oct-1990 L. Rooijakkers
* 07-Feb-1991 L. Rooijakkers indexing, embedded options
* 08-Feb-1991 L. Rooijakkers small mods for version 1.0 #0
* 12-Feb-1991 L. Rooijakkers minor portability fixes
*
*/
#ifndef lint
static char SccsId[]="@(#)rail 12-Feb-1991";
#endif
#define USAGE "usage: %s [-+acdit] [file]\n"
#include <stdio.h>
#include "patchlev.h"
#include "rail.h"
#include "gram.h"
extern char *strcat(), *strcpy();
char *myname; /* program name */
char *file; /* input file */
int my_line; /* input line */
extern FILE *yyin; /* lex input stream */
char *outfile; /* output file */
FILE *outf; /* output stream */
int newline; /* stdout requires a newline */
IDTYPE *idlist; /* identifier list */
IDTYPE *errorid; /* identifier for errors */
/* options */
int altstar; /* alternate star */
int chkgram; /* check grammar */
int treelist; /* list rule trees */
int genindex; /* generate index entry for left hand sides */
#ifdef YYDEBUG
extern int yydebug; /* show yacc debugging */
#endif
int anonymous; /* anonymous rules */
main(argc,argv)
int argc;
char **argv;
{
char *arg, **argp;
unsigned len;
printf("This is Rail, Version %s #%d\n",VERSION,PATCHLEVEL);
newline=0;
myname=argv[0];
for(argp = &argv[1];(arg = *argp)!=NULL;argp++) {
if(*arg!='-' && *arg!='+')
break;
if(setopt(*arg,arg+1)==0)
usage();
}
if(arg!=NULL && *++argp!=NULL)
usage();
if(arg==NULL) {
file="stdin";
outfile="stdout";
yyin=stdin;
outf=stdout;
} else {
len=strlen(arg)+5;
file=mcheck(malloc(len));
outfile=mcheck(malloc(len));
strcat(strcpy(file,arg),".rai");
strcat(strcpy(outfile,arg),".rao");
if((yyin=fopen(file,"r"))==NULL) {
perror(file);
exit(1);
}
if((outf=fopen(outfile,"w"))==NULL) {
perror(outfile);
exit(1);
}
}
printf("(%s",file);
newline=1;
my_line=1;
fprintf(outf,"%% This file was generated by '%s' from '%s'\n",myname,file);
if(yyparse()!=0)
exit(1);
printf(")\n");
newline=0;
file=NULL;
if(chkgram) {
checkdefs();
if(anonymous)
error("unnamed rules are present",(char *)NULL);
}
exit(0);
/*NOTREACHED*/
}
int setopt(c,s)
char c, *s;
{
int set;
set = c=='-';
while(*s!='\0') {
switch(*s++) {
case 'a':
altstar=set;
break;
case 'c':
chkgram=set;
break;
case 'd':
#ifdef YYDEBUG
yydebug=set;
#endif
break;
case 'i':
genindex=set;
break;
case 't':
treelist=set;
break;
default:
return 0;
}
}
return 1;
}
usage()
{
fprintf(stderr,USAGE,myname);
exit(1);
}
/* error routine for yyparse() */
yyerror(s)
char *s;
{
fatal("%s",s);
}
/* wrap-up routine for yylex() */
yywrap()
{
return(1);
}
/* check for non-NULL pointer */
char *mcheck(s)
char *s;
{
if(s==NULL)
fatal("out of memory",(char *)NULL);
return(s);
}
/* make a new body */
BODYTYPE *newbody(kind,body1,body2)
int kind;
BODYTYPE *body1, *body2;
{
BODYTYPE *body;
body=(BODYTYPE *)mcheck(malloc(sizeof(BODYTYPE)));
body->kind=kind;
body->nlist=0;
body->done=0;
body->id=NULL;
body->text=NULL;
body->annot=NULL;
if(body1!=NULL)
body->list[body->nlist++]=body1;
if(body2!=NULL)
body->list[body->nlist++]=body2;
return(body);
}
/* free a body recursively */
freebody(body)
BODYTYPE *body;
{
int i;
if(body==NULL)
return;
for(i=0;i<body->nlist;i++)
freebody(body->list[i]);
if(body->text!=NULL) {
/* should free text here */
}
free((char *)body);
}
/* test if a body is empty */
int isemptybody(body)
BODYTYPE *body;
{
return(body==NULL || body->kind==EMPTY);
}
/* add to a body list */
static addlist(body1,body2)
BODYTYPE *body1, *body2;
{
if(body1->nlist>=MAXLIST) {
yyerror("list too long");
} else
body1->list[body1->nlist++]=body2;
}
/* add two body lists (for CAT, BAR, PLUS) */
BODYTYPE *addbody(kind,body1,body2)
int kind;
BODYTYPE *body1, *body2;
{
BODYTYPE *body;
int i;
if(body1->kind==kind && !(kind==BAR && body1->done) ) {
body=body1;
} else {
body=newbody(kind,NULLBODY,NULLBODY);
addlist(body,body1);
}
if(body2->kind==kind && !(kind==BAR && body2->done) ) {
for(i=0;i<body2->nlist;i++)
addlist(body,body2->list[i]);
free((char *)body2);
} else {
addlist(body,body2);
}
return(body);
}
/* reverse all concatenations (for PLUS) */
BODYTYPE *revbody(body)
BODYTYPE *body;
{
int i,j;
BODYTYPE *tmp;
if(body->kind==CAT) {
for(i=0,j=body->nlist-1;i<j;i++,j--) {
tmp=body->list[i];
body->list[i]=body->list[j];
body->list[j]=tmp;
}
}
for(i=0;i<body->nlist;i++)
body->list[i]=revbody(body->list[i]);
return(body);
}
/* print a body for debugging */
prtbody(indent,body)
int indent;
BODYTYPE *body;
{
int i;
fprintf(outf,"%% ");
for(i=0;i<indent;i++)
fprintf(outf,". ");
if(body==NULL)
fprintf(outf,"NULL\n");
else {
switch(body->kind) {
case EMPTY:
fprintf(outf,"EMPTY");
break;
case CAT:
fprintf(outf,"CAT");
break;
case BAR:
fprintf(outf,"BAR");
break;
case PLUS:
fprintf(outf,"PLUS");
break;
case ANNOTE:
fprintf(outf,"ANNOTE [%s]",body->text);
break;
case IDENT:
fprintf(outf,"IDENT %s",body->id->name);
break;
case CR:
fprintf(outf,"CR");
break;
case STRNG:
fprintf(outf,"STRNG '%s'",body->text);
break;
default:
fprintf(outf,"UNKNOWN");
break;
}
fprintf(outf," y=%d nexty=%d\n",body->ystart,body->ynext);
for(i=0;i<body->nlist;i++)
prtbody(indent+1,body->list[i]);
}
}
/* output a body */
outbody(id,body)
IDTYPE *id;
BODYTYPE *body;
{
posbody(body,0);
if(treelist)
prtbody(0,body);
fprintf(outf,"\\rail@begin{%d}{",body->ynext);
if(id!=NULL) {
fprintf(outf,"%s",id->name);
}
fprintf(outf,"}\n");
fmtbody(body,"");
fprintf(outf,"\\rail@end\n");
}
/* format a body */
fmtbody(body,cent)
BODYTYPE *body;
char *cent;
{
BODYTYPE *body1;
int i;
char *next;
switch(body->kind) {
case EMPTY:
break;
case CAT:
for(i=0;i<body->nlist;i++)
fmtbody(body->list[i],"");
break;
case BAR:
next="\\rail@bar\n";
for(i=0;i<body->nlist;i++) {
body1=body->list[i];
fprintf(outf,next,body1->ystart);
next="\\rail@nextbar{%d}\n";
fmtbody(body1,"");
}
fprintf(outf,"\\rail@endbar\n");
break;
case PLUS:
fprintf(outf,"\\rail@plus\n");
fmtbody(body->list[0],"");
body1=body->list[1];
fprintf(outf,"\\rail@nextplus{%d}\n",body1->ystart);
fmtbody(body1,"c");
fprintf(outf,"\\rail@endplus\n");
break;
case ANNOTE:
fprintf(outf,"\\rail@annote[%s]\n",body->text);
break;
case IDENT:
if(body->id->kind==TERM)
fprintf(outf,"\\rail@%stoken{%s",cent,body->id->name);
else
fprintf(outf,"\\rail@%snont{%s",cent,body->id->name);
if(body->annot!=NULL)
fprintf(outf,"\\rail@annotebox[%s]",body->annot);
fprintf(outf,"}\n");
break;
case CR:
fprintf(outf,"\\rail@cr{%d}\n",body->ynext-1);
break;
case STRNG:
fprintf(outf,"\\rail@%sterm{%s",cent,body->text);
if(body->annot!=NULL)
fprintf(outf,"\\rail@annotebox[%s]",body->annot);
fprintf(outf,"}\n");
break;
default:
fprintf(outf,"\\rail@unknown\n");
break;
}
}
/* position body (fill in height and ystart) */
posbody(body,ystart)
BODYTYPE *body;
{
BODYTYPE *body1;
int i;
switch(body->kind) {
case CAT:
body->ystart=ystart;
body->ynext=ystart+1;
for(i=0;i<body->nlist;i++) {
body1=body->list[i];
if(body1->kind==CR) {
body1->ystart=ystart;
body1->ynext=body->ynext+2;
ystart=body1->ynext-1;
} else
posbody(body1,ystart);
if(body1->ynext>body->ynext)
body->ynext=body1->ynext;
}
break;
case BAR:
case PLUS:
body->ystart=ystart;
body->ynext=ystart+1;
for(i=0;i<body->nlist;i++) {
body1=body->list[i];
posbody(body1,ystart);
ystart=body1->ynext;
if(body1->ynext>body->ynext)
body->ynext=body1->ynext;
}
break;
case CR:
body->ystart=ystart;
body->ynext=ystart+3;
break;
case EMPTY:
case ANNOTE:
case IDENT:
case STRNG:
default:
body->ystart=ystart;
body->ynext=ystart+1;
break;
}
}
/* output an index entry */
outindex(id)
IDTYPE *id;
{
if(id!=NULL)
fprintf(outf,"\\rail@index{%s}\n",id